//
//  FreeBSDSocket.h
//  AirCpp
//
//  Created by Penghao on 14-4-10.
//  Copyright (c) 2014年 PengHao. All rights reserved.
//

#ifndef __AirCpp__FreeBSDSocket__
#define __AirCpp__FreeBSDSocket__

#include <sys/types.h>   /* basic system data types */
#include <sys/socket.h>  /* basic socket definitions */
#include <sys/time.h>    /* timeval{} for select() */
#include <time.h>        /* timespec{} for pselect() */
#include <netinet/in.h>  /* sockaddr_in{} and other Internet defns */
#include <arpa/inet.h>   /* inet(3) functions */
#include <errno.h>
#include <fcntl.h>       /* for nonblocking */
#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>    /* for S_xxx file mode constants */
#include <sys/uio.h>     /* for iovec{} and readv/writev */
#include <unistd.h>
#include <sys/wait.h>
#include <sys/un.h>      /* for Unix domain sockets */
#include <sys/event.h>
#include "AirBSDSocket.h"
#include "AirBSDSocketListener.h"
#include "AirBSDSocketIO.h"
namespace AirCpp{
    
    template <class CallBack>
    class AirFreeBSDSocketListener : public AirBSDSocketListener<CallBack> {
    protected:
        struct kevent ev;
        
        struct timespec ts = { 10, 0 }, ts1 = {0,0};
        int kq;
    public:
        
        AirFreeBSDSocketListener(CallBack *call_back):AirBSDSocketListener<CallBack>(call_back){
        }
        
        int start_listen(CallBack *_target){
            this->is_starting = true;
            this->callback_target = _target;
            if (AirBSDSocket<CallBack>::socketHandle < 0) {
                DebugLog("this socketHandle havn't be init");
                return -1;
            }
            //初始化该队列
            this->kq = kqueue();
            DebugLog("start listen socketHandle %d", this->socketHandle);
            EV_SET( &this->ev, this->socketHandle, EVFILT_READ|EVFILT_WRITE, EV_ADD|EV_ENABLE, 0,0,0);
            kevent(this->kq, &this->ev, 1, NULL, 0, &this->ts1);

            while (this->is_starting) {
                //等待IO可用
                switch (kevent(this->kq, NULL, 0, &this->ev, 1, &this->ts)) {
                    case -1:
                        printf("kevent(4)");
                        exit(1);
                        break;
                        
                    case 0:
                        printf("listen TIMEOUT /n");
                        continue;
                        
                    default:
                        if( this->ev.ident == this->socketHandle)
                        {
                            //listen
                            printf("listened!");
                            sockaddr client_addr;
                            socklen_t client_size;
                            this->accept_connection(&client_addr, &client_size);
                        }
                        break;
                }
            }
            return 0;
        }
    };
}

#endif /* defined(__AirCpp__FreeBSDSocket__) */
